#import "DnpPlugin.h"
#import "DnpFB.h"
#import "DnpNet.h"
#import "DnpWifi.h"
#import "DnpToast.h"
#import "DnpAlert.h"
#import "DnpMemory.h"
#import "DnpBattery.h"
#import "DnpLoading.h"
#import "DnpLocation.h"
#import "DnpEquipment.h"
#import "DnpActionSheet.h"
#import "DnpContactManager.h"
#import "DnpLocationTracking.h"
#import "DnpChooseAlbumDelegate.h"
#import "DnpPickerImageDelegate.h"
#import "DnpChooseContactDelegate.h"

#import <Photos/Photos.h>
#import <Contacts/Contacts.h>
#import <StoreKit/StoreKit.h>

@interface DnpPlugin()

@property (nonatomic,strong) DnpPickerImageDelegate *pickerDelegate;

@property (nonatomic,strong) DnpContactDelegate *contactDelegate;

@property (nonatomic,strong) DnpLocationTracking *locationTracking;

@end

@implementation DnpPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:@"dnp_plugin"
                                     binaryMessenger:[registrar messenger]];
    DnpPlugin* instance = [[DnpPlugin alloc] init];
    [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    
    if ([@"fearlessness" isEqualToString:call.method]) {
        result([DnpEquipment fearlessness]);
    } else if ([@"footed" isEqualToString:call.method]) {
        result([DnpEquipment footed]);
    } else if ([@"holiday" isEqualToString:call.method]) {
        result([DnpEquipment holiday]);
    } else if ([@"considerably" isEqualToString:call.method]) {
        result([DnpEquipment considerably]);
    } else if ([@"sysName" isEqualToString:call.method]) {
        result([DnpEquipment sysName]);
    } else if ([@"cannot" isEqualToString:call.method]) {
        result([DnpEquipment cannot]);
    } else if ([@"afford" isEqualToString:call.method]) {
        result([DnpEquipment afford]);
    } else if ([@"largest" isEqualToString:call.method]) {
        result([DnpEquipment largest]);
    } else if ([@"autou" isEqualToString:call.method]) {
        result([DnpEquipment autou]);
    } else if ([@"ten" isEqualToString:call.method]) {
        result([DnpEquipment ten]);
    } else if ([@"should" isEqualToString:call.method]) {
        result([DnpEquipment should]);
    } else if ([@"finger" isEqualToString:call.method]) {
        result([DnpNet finger]);
    } else if ([@"showToast" isEqualToString:call.method]) {
        [self showToast:call];
    } else if ([@"showAlert" isEqualToString:call.method]) {
        [self showAlert:call];
    } else if ([@"openHud" isEqualToString:call.method]) {
        [self openHud];
    } else if ([@"closeHud" isEqualToString:call.method]) {
        [self closeHud];
    } else if ([@"submitFB" isEqualToString:call.method]) {
        [self submitFB:call];
    } else if ([@"showSKStore" isEqualToString:call.method]) {
        [self showSKStore];
    } else if ([@"showActionSheet" isEqualToString:call.method]) {
        [self showActionSheet:result];
    } else if ([@"showFrontCamera" isEqualToString:call.method]) {
        [self showFrontCamera:result];
    } else if ([@"chooseContact" isEqualToString:call.method]) {
        [self chooseContact:result];
    } else if ([@"chooseContactList" isEqualToString:call.method]) {
        [self chooseContactList:result];
    } else if ([@"treasures" isEqualToString:call.method]) {
        result([DnpMemory treasures]);
    } else if ([@"indescribable" isEqualToString:call.method]) {
        [self indescribable:result];
    } else if ([@"startLocationTracking" isEqualToString:call.method]) {
        [self startLocationTracking:result];
    } else if ([@"endLocationTracking" isEqualToString:call.method]) {
        [self endLocationTracking];
    } else if ([@"shook" isEqualToString:call.method]) {
        result([DnpWifi shook]);
    } else if ([@"wire" isEqualToString:call.method]) {
        result([[DnpBattery manager] wire]);
    } else if ([@"isPad" isEqualToString:call.method]) {
        BOOL isPad = [[UIDevice currentDevice].model isEqualToString:@"iPad"];
        result(@(isPad));
    } else {
        result(FlutterMethodNotImplemented);
    }
}


#pragma mark - showToast

- (void)showToast:(FlutterMethodCall*)call {
    NSString *text = call.arguments;
    [DnpToast show:text];
}

#pragma mark - showAlert

- (void)showAlert:(FlutterMethodCall*)call {
    NSString *text = call.arguments;
    [DnpAlert show:text];
}

#pragma mark - submitFB

- (void)submitFB:(FlutterMethodCall*)call {
    [DnpFB report:call.arguments];
}

#pragma mark - showSKStore

- (void)showSKStore {
    if (@available(iOS 14.0, *)) {
          UIScene *windowScene = [UIApplication sharedApplication].connectedScenes.allObjects.firstObject;
          if ([windowScene isKindOfClass:[UIWindowScene class]]) {
              [SKStoreReviewController requestReviewInScene:(UIWindowScene *)windowScene];
          }
      }
}

#pragma mark - openHud

- (void)openHud {
    [[DnpLoading shareInstance] open];
}

#pragma mark - closeHud

- (void)closeHud {
    [[DnpLoading shareInstance] close];
}

#pragma mark - showActionSheet

- (void)showActionSheet:(FlutterResult)result {
    UIViewController *controller = [self currentController];
    if (controller) {
        [DnpActionSheet show:controller completion:^(BOOL selectedFromAlbum) {
            if (selectedFromAlbum) {
                [self verifyAlbumAccessWithController:controller result:result];
            }else {
                [self verifyCameraAccessWithController:controller result:result];
            }
        }];
    }
}

- (void)showFrontCamera:(FlutterResult)result {
    UIViewController *controller = [self currentController];
    if (controller) {
        AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
            
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (granted) {
                    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
                        [self openCameraWithController:controller result:result device:UIImagePickerControllerCameraDeviceFront];
                    }
                } else {
                    if (status == AVAuthorizationStatusDenied) {
                        [DnpAlert show:@"Please grant permission to access the Camera in Settings."];
                    }
                }
            });
        }];
    }
}

- (void)verifyAlbumAccessWithController:(UIViewController *)controller result:(FlutterResult)result {
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (status == PHAuthorizationStatusAuthorized) {
                [self openAlbumWithController:controller result:result];
            } else if (status == PHAuthorizationStatusDenied) {
                [DnpAlert show:@"Please grant permission to access the Photo Library in Settings."];
            }
        });
    }];
}

- (void)verifyCameraAccessWithController:(UIViewController *)controller result:(FlutterResult)result {
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        
    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (granted) {
                if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
                    [self openCameraWithController:controller result:result device:UIImagePickerControllerCameraDeviceRear];
                }
            } else {
                if (status == AVAuthorizationStatusDenied) {
                    [DnpAlert show:@"Please grant permission to access the Camera in Settings."];
                }
            }
        });
    }];
}

- (void)openAlbumWithController:(UIViewController *)controller result:(FlutterResult)result {
    if (@available(iOS 9.0, *)) {
        self.pickerDelegate = [[DnpChooseAlbumDelegate alloc] initWithResult:result];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
            pickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
            pickerController.delegate = self.pickerDelegate;
            pickerController.allowsEditing = YES;
            [controller presentViewController:pickerController animated:YES completion:nil];
        });
    }
}

- (void)openCameraWithController:(UIViewController *)controller result:(FlutterResult)result device:(UIImagePickerControllerCameraDevice)device {
    if (@available(iOS 9.0, *)) {
        self.pickerDelegate = [[DnpChooseAlbumDelegate alloc] initWithResult:result];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
            pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
            pickerController.delegate = self.pickerDelegate;
            pickerController.cameraDevice = device;
            [controller presentViewController:pickerController animated:YES completion:nil];
        });
    }
}

#pragma mark - chooseContact

- (void)chooseContact:(FlutterResult)result {
    
    UIViewController *controller = [self currentController];
    
    CNContactStore *store = [[CNContactStore alloc] init];
        
    [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            self.contactDelegate = [[DnpChooseContactDelegate alloc] initWithResult:result];
            dispatch_async(dispatch_get_main_queue(), ^{
                CNContactPickerViewController *contactPicker = [[CNContactPickerViewController alloc] init];
                contactPicker.delegate = self.contactDelegate;
                contactPicker.displayedPropertyKeys = @[CNContactPhoneNumbersKey];
                [controller presentViewController:contactPicker animated:YES completion:nil];
            });
            
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                [DnpAlert show:@"Please grant permission to access the Contacts in Settings."];
            });
        }
    }];
}

#pragma mark - chooseContacts

- (void)chooseContactList:(FlutterResult)result {
    [DnpContactManager chooseContactsCompletion:^(NSArray<NSDictionary *> * _Nonnull contacts) {
        result(contacts);
    }];
}

#pragma mark - indescribable

- (void)indescribable:(FlutterResult)result {
    DnpLocation *lo = [DnpLocation sharedInstance];
    lo.locationHander = ^(NSDictionary * _Nonnull info) {
        result(info);
    };
    [lo beginUpdates];
    
}

#pragma mark - startLocationTracking

- (void)startLocationTracking:(FlutterResult)result {
    [self.locationTracking beginUpdates];
    self.locationTracking.locationHander = ^(NSDictionary * _Nonnull info) {
        result(info);
    };
}

#pragma mark - endLocationTracking

- (void)endLocationTracking{
    [self.locationTracking endUpdates];
}

- (UIViewController *)currentController {
    UIWindow *keyWindow = nil;
    if (@available(iOS 13.0, *)) {
        for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
            if ([scene isKindOfClass:[UIWindowScene class]]) {
                UIWindowScene *windowScene = (UIWindowScene *)scene;
                if (windowScene.activationState == UISceneActivationStateForegroundActive) {
                    keyWindow = windowScene.windows.firstObject;
                    if (keyWindow.isKeyWindow) {
                        break;
                    }
                }
            }
        }
    } else {
        keyWindow = [UIApplication sharedApplication].keyWindow;
    }
    
    UIViewController *rootViewController = keyWindow.rootViewController;
    return rootViewController ? rootViewController : nil;
}

#pragma mark - lazy

- (DnpLocationTracking *)locationTracking {
    if (!_locationTracking) {
        _locationTracking = [[DnpLocationTracking alloc] init];
    }
    return _locationTracking;
}

@end
